import json
import re
import uuid
from decimal import Decimal

from django.db import connection
from django.http import HttpResponse
from django.shortcuts import render

# Create your views here.
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.decorators import action, api_view, authentication_classes
from rest_framework.filters import SearchFilter, OrderingFilter
from rest_framework.generics import GenericAPIView
from rest_framework.views import APIView
from rest_framework.viewsets import ModelViewSet

from base.views import BaseView, NoChangeModelViewSet
from contract.db_util.db_util import dictfetchall, DateEncoder
from mineral.models import *
from mineral.serializers import *

# 供应商管理
from utils.excel_util import style_excel
from utils.jwtAuth import JWTAuthentication
from utils.pagination import Pagination
from utils.permissions import BaseAuthPermission, AllowAllPermission
from utils.utils import VisitThrottle
from rest_framework.response import Response
from rest_framework import generics, mixins, views
from rest_framework.viewsets import GenericViewSet
from rest_framework.response import Response
from rest_framework import status


# 矿物种类管理
class MineralTypeViewset(BaseView):
    '''矿物种类管理'''
    queryset = MineralType.objects.all().order_by('-create_time')
    authentication_classes = (JWTAuthentication,)
    permission_classes = [BaseAuthPermission, ]
    throttle_classes = [VisitThrottle]
    serializer_class = MineralTypeSerializer
    filter_backends = (DjangoFilterBackend, SearchFilter, OrderingFilter,)
    search_fields = ('name',)
    ordering_fields = ('name', 'update_time', 'create_time',)
    pagination_class = Pagination

    add_hidden_fields = ('quantity',)
    edit_hidden_fields = ('quantity',)

    def get_serializer_class(self):
        if self.action in ['list', 'get_insurance_model']:
            return ListMineralTypeSerializer
        else:
            return MineralTypeSerializer


# 货品管理
class ProductViewset(BaseView):
    '''货品管理'''
    queryset = Product.objects.all().order_by('-create_time')
    authentication_classes = (JWTAuthentication,)
    permission_classes = [BaseAuthPermission, ]
    throttle_classes = [VisitThrottle]
    serializer_class = ProductSerializer
    filter_backends = (DjangoFilterBackend, SearchFilter, OrderingFilter,)
    search_fields = ('name',)
    filterset_fields = ['mineral_type__name']
    ordering_fields = ('name', 'update_time', 'create_time',)
    pagination_class = Pagination

    def get_serializer_class(self):
        if self.action in ['list', 'get_insurance_model']:
            return ProductSerializer
        else:
            return EditProductSerializer

    # 获得没有初始化库存的所有产品
    @action(methods=['get'], detail=False, permission_classes=[AllowAllPermission])
    def get_no_inventory_product(self, request):
        products = Product.objects.filter(inventory__isnull=True)
        serializer = ProductSerializer(products, many=True)
        return Response(serializer.data)


# 库存执行管理
class InventoryPerformViewset(NoChangeModelViewSet):
    '''库存执行管理'''
    queryset = InventoryPerform.objects.all().order_by('-create_time')
    authentication_classes = (JWTAuthentication,)
    permission_classes = [BaseAuthPermission, ]
    throttle_classes = [VisitThrottle]
    serializer_class = InventoryPerformSerializer
    filter_backends = (DjangoFilterBackend, SearchFilter, OrderingFilter,)
    search_fields = ('product__name',)
    ordering_fields = ('product__name', 'update_time', 'create_time',)
    filterset_fields = ['operation_type']
    pagination_class = Pagination
    add_hidden_fields = ('inventory_after_requisition', 'create_time')
    edit_hidden_fields = ('inventory_after_requisition',)

    def get_serializer_class(self):
        if self.action in ['list', 'get_insurance_model']:
            return ListInventoryPerformSerializer
        else:
            return InventoryPerformSerializer


# 库存管理
class InventoryViewset(NoChangeModelViewSet, mixins.RetrieveModelMixin, mixins.UpdateModelMixin):
    '''库存管理'''
    queryset = Inventory.objects.all().order_by('-create_time')
    authentication_classes = (JWTAuthentication,)
    permission_classes = [BaseAuthPermission, ]
    throttle_classes = [VisitThrottle]
    serializer_class = InventorySerializer
    filter_backends = (DjangoFilterBackend, SearchFilter, OrderingFilter,)
    search_fields = ('product__name',)
    ordering_fields = ('product__name', 'update_time', 'create_time',)
    pagination_class = Pagination
    add_hidden_fields = ('daily_consumption',)
    edit_hidden_fields = ('daily_consumption',)
    column_hidden_fields = ('daily_consumption',)

    def get_serializer_class(self):
        if self.action in ['list', 'get_insurance_model']:
            return ListInventorySerializer
        else:
            return InventorySerializer


# 生产计划管理
class ProductionPlanViewset(BaseView):
    '''生产计划管理'''
    queryset = ProductionPlan.objects.all().order_by('-create_time')
    authentication_classes = (JWTAuthentication,)
    permission_classes = [BaseAuthPermission, ]
    throttle_classes = [VisitThrottle]
    serializer_class = ProductionPlanSerializer
    filter_backends = (DjangoFilterBackend, SearchFilter, OrderingFilter,)
    search_fields = ('product__name',)
    ordering_fields = ('product__name', 'update_time', 'create_time',)
    pagination_class = Pagination
    # 自定义字段
    add_hidden_fields = ('days_available',)
    edit_hidden_fields = ('days_available',)
    column_hidden_fields = ('days_available',)

    def get_serializer_class(self):
        if self.action in ['list', 'get_insurance_model']:
            return ListProductionPlanSerializer
        else:
            return ProductionPlanSerializer


class PurchasePlanView(BaseView):
    '''采购计划管理'''
    queryset = PurchasePlan.objects.all().order_by('-create_time')
    authentication_classes = (JWTAuthentication,)
    permission_classes = [BaseAuthPermission, ]
    throttle_classes = [VisitThrottle]
    serializer_class = PurchasePlanSerializer
    filter_backends = (DjangoFilterBackend, SearchFilter, OrderingFilter,)
    search_fields = ('product__name',)
    ordering_fields = ('product__name', 'update_time', 'create_time',)
    pagination_class = Pagination

    def get_serializer_class(self):
        if self.action in ['list', 'get_insurance_model']:
            return ListPurchasePlanSerializer
        else:
            return PurchasePlanSerializer


# --------------------综合报表视图 相关
# pc端获得字典数据
def getComprehensiveReport():
    sql = '''select a.id,a.name as type_name,a.quantity,b.name as product_name,c.plant_quantity,
c.not_arrival_port_quantity,
c.not_arrival_port_note,
c.port_quantity,
    d.daily_consumption,a.safe_day,
    d.daily_consumption * a.safe_day as safe_inventory,   a.quantity/d.daily_consumption as available_day,
    e.last_parchase_date,e.purchase_quantity,e.actual_purchase_quantity
    from inventory c
    right join product b on  c.product_id = b.id  
    left join mineral_type a  on a.id = b.mineral_type_id
    left join production_plan d on d.mineral_type_id = a.id
    left join purchase_plan e on e.product_id = b.id
    order by a.id
    '''

    cur = connection.cursor()
    cur.execute(sql)
    data = dictfetchall(cur)
    cur.close()
    return data


def getComprehensiveReport2():
    sql = '''select a.id,a.name as type_name,
case 
	when f.plant_quantity is null 
    then c.plant_quantity + c.not_arrival_port_quantity + c.port_quantity 
    else f.plant_quantity
end as quantity,
b.name as product_name,c.plant_quantity,
    c.not_arrival_port_quantity,
    c.not_arrival_port_note,
    c.port_quantity,
        a.safe_day,
        f.daily_consumption * a.safe_day as safe_inventory,   a.quantity/d.daily_consumption as available_day,
        e.last_parchase_date,
        case 
			when f.requirement_planning is null
            then e.purchase_quantity
            else f.requirement_planning
		end as purchase_quantity,
        e.actual_purchase_quantity,
        b.product_group_id,
		case
			when f.daily_consumption is null
            then b.daily_consumption
            else f.daily_consumption
		end as daily_consumption,
        f.requirement_planning,f.plant_quantity as total_number,
        case
			when f.in_plant_quantity is null
            then c.plant_quantity + c.port_quantity
            else f.in_plant_quantity
		end as in_plant_quantity
        from inventory c
        right join product b on  c.product_id = b.id  
        left join mineral_type a  on a.id = b.mineral_type_id
        left join production_plan d on d.mineral_type_id = a.id
        left join purchase_plan e on e.product_id = b.id
        left join product_group f on f.id = b.product_group_id
		where c.plant_quantity is not null
        order by a.name,b.product_group_id
        '''

    cur = connection.cursor()
    cur.execute(sql)
    data = dictfetchall(cur)
    cur.close()
    return data


# 小程序端获得数据
def getComprehensiveReportNoDict():
    sql = '''select a.name as type_name,a.quantity,b.name as product_name,c.plant_quantity,
c.not_arrival_port_quantity,
c.not_arrival_port_note,
c.port_quantity,
    d.daily_consumption,a.safe_day,
    d.daily_consumption * a.safe_day as safe_inventory,   a.quantity/d.daily_consumption as available_day,
    e.last_parchase_date,e.purchase_quantity,e.actual_purchase_quantity
        from inventory c
        right join product b on  c.product_id = b.id  
        left join mineral_type a  on a.id = b.mineral_type_id
        left join production_plan d on d.mineral_type_id = a.id
        left join purchase_plan e on e.product_id = b.id
        order by a.id
        '''

    cur = connection.cursor()
    cur.execute(sql)
    data = cur.fetchall()
    cur.close()
    return data


def getComprehensiveReportNoDict2():
    sql = '''select a.id,a.name as type_name,
case 
	when f.plant_quantity is null 
    then c.plant_quantity + c.not_arrival_port_quantity + c.port_quantity 
    else f.plant_quantity
end as quantity,
b.name as product_name,c.plant_quantity,
    c.not_arrival_port_quantity,
    c.not_arrival_port_note,
    c.port_quantity,
        a.safe_day,
        f.daily_consumption * a.safe_day as safe_inventory,   a.quantity/d.daily_consumption as available_day,
        e.last_parchase_date,
        case 
			when f.requirement_planning is null
            then e.purchase_quantity
            else f.requirement_planning
		end as purchase_quantity,
        e.actual_purchase_quantity,
        b.product_group_id,
		case
			when f.daily_consumption is null
            then b.daily_consumption
            else f.daily_consumption
		end as daily_consumption,
        f.requirement_planning,f.plant_quantity as total_number
        from inventory c
        right join product b on  c.product_id = b.id  
        left join mineral_type a  on a.id = b.mineral_type_id
        left join production_plan d on d.mineral_type_id = a.id
        left join purchase_plan e on e.product_id = b.id
        left join product_group f on f.id = b.product_group_id
		where c.plant_quantity is not null 
        order by a.name,b.product_group_id 
            '''

    cur = connection.cursor()
    cur.execute(sql)
    data = cur.fetchall()
    cur.close()
    return data


# 添加合计值到综合报表中
def addCategoryTotal(data):
    """
    添加合计值到综合报表中 为了兼容跨行逻辑 需要注意跨行逻辑中关键值的处理
    关键之主要包括 id 和 product_group_id
    这里 id 和 product_group_id 都用uuid处理成唯一值，使其单独作为一行
    """
    data_temp = {'id': 3, 'type_name': '块矿', 'quantity': Decimal('62599.90'), 'product_name': '',
                 'plant_quantity': Decimal('12599.90'), 'not_arrival_port_quantity': Decimal('50000.00'),
                 'not_arrival_port_note': None, 'port_quantity': Decimal('0.00'), 'safe_day': Decimal('20.00'),
                 'safe_inventory': None, 'available_day': None, 'last_parchase_date': None, 'purchase_quantity': None,
                 'actual_purchase_quantity': None, 'product_group_id': '671886d8-4a77-11ec-952f-18c04d302348',
                 'daily_consumption': Decimal('0.00'), 'requirement_planning': None, 'total_number': None,
                 'summation': True}

    # 这里获得大类尾行的index,在此处添加合计值
    type_id = data[0]['id']
    index_json = {}
    for index, value in enumerate(data):
        if type_id == value['id']:
            pass
        else:
            index_json[type_id] = index
            type_id = value['id']

    index_json[type_id] = len(data) + 1

    # 这里进行插入合计值的操作
    query = MineralType.objects.all()
    count = 0
    for key in index_json:
        for i in query:
            if key == i.id:
                index = index_json[key]
                data_temp['type_name'] = i.name + '合计：'
                data_temp['quantity'] = i.quantity

                # 这里 id 和 product_group_id 关键值作唯一值处理
                data_temp['id'] = str(uuid.uuid1())
                data_temp['product_group_id'] = str(uuid.uuid1())

                inventorys = Inventory.objects.filter(product__mineral_type_id=i.id)
                data_temp['plant_quantity'] = 0
                data_temp['port_quantity'] = 0
                data_temp['not_arrival_port_quantity'] = 0
                for inventory in inventorys:
                    data_temp['plant_quantity'] += inventory.plant_quantity
                    data_temp['port_quantity'] += inventory.port_quantity
                    data_temp['not_arrival_port_quantity'] += inventory.not_arrival_port_quantity

                data.insert(index + count, deepcopy(data_temp))
                # insert操作使data长度+1 所以insert操作后需要进行 count+1
                # 这里外循环 必须是 index_json,根据实际的排序循环，否则导致表格展示顺序出现错误
                count += 1
    return index_json


# 处理跨行逻辑
def rowspanLogic(data):
    arr = []
    # 用于判断 是否同一种类
    type_id = None
    if len(data) > 0:
        type_id = data[0]['id']
    temp = {"rowspan": 0, "startIndex": 0, "endIndex": 0}
    for index, value in enumerate(data):
        if type_id == value['id']:
            # print(index, data[index]['id'], 'rowspan+', temp['rowspan'])
            temp['rowspan'] += 1
            temp['endIndex'] = temp['startIndex'] + temp['rowspan']
        else:
            temp['endIndex'] = temp['startIndex'] + temp['rowspan']
            # print(index, data[index]['id'], 'append', temp['rowspan'])
            arr.append(temp)

            # 重置
            type_id = value['id']
            temp = {"rowspan": 1, "startIndex": temp['endIndex'], "endIndex": temp['endIndex'] + 1}

    # 处理最后一次循环
    arr.append(temp)
    return arr


def rowspanLogic2(data):
    """
    只处理跨行，不涉及跨列
    这一部分 跨行逻辑 比较复杂  需要结合 elementui 表格组件跨行逻辑理解
    rowspan 跨行
    colspan 跨列
    rowspan = 1 colspan = 1 表示 不跨行
    rowspan = 0 colspan = 0 表示 被 跨行的单元占用的单元格 隐藏
    rowspan colspan 数字大小等于 跨行数量 被占用的单元格需要 使用 rowspan = 0,colspan = 0 隐藏，否则对不齐
    """
    arr = []
    # 用于判断 是否同一种类
    type_id = None
    if len(data) > 0:
        for item in data:
            if item['product_group_id'] is None:
                item['product_group_id'] = str(uuid.uuid1())
        type_id = data[0]['product_group_id']

    temp = {"rowspan": 0, "startIndex": 0, "endIndex": 0}
    for index, value in enumerate(data):
        if type_id == value['product_group_id']:
            # print(index, data[index]['id'], 'rowspan+', temp['rowspan'])
            temp['rowspan'] += 1
            temp['endIndex'] = temp['startIndex'] + temp['rowspan']
        else:
            temp['endIndex'] = temp['startIndex'] + temp['rowspan']
            # print(index, data[index]['id'], 'append', temp['rowspan'])
            arr.append(temp)

            # 重置
            type_id = value['product_group_id']
            temp = {"rowspan": 1, "startIndex": temp['endIndex'], "endIndex": temp['endIndex'] + 1}

    # 处理最后一次循环
    arr.append(temp)

    return arr


class ReportView(APIView):
    authentication_classes = [JWTAuthentication]

    # 获得综合报表
    def get(self, request, *args, **kwargs):
        data = getComprehensiveReport2()

        # 添加合计值到data
        index_json = addCategoryTotal(data)

        # ---------  处理 跨行逻辑
        arr = rowspanLogic2(data)
        # 处理第一列的跨行逻辑
        first_arr = rowspanLogic(data)

        for i in data:
            if i['daily_consumption'] is not None and i['daily_consumption'] != 0:
                # 计算总库存安全天数  保留两位小数
                i['available_day'] = round(i['quantity'] / i['daily_consumption'], 2)
                # 计算厂内库存安全天数 保留两位小数
                i['plant_quantity_available_day'] = round(i['in_plant_quantity'] / i['daily_consumption'], 2)
            else:
                i['available_day'] = None

        return HttpResponse(
            json.dumps({"data": data, "arr": arr, "first_arr": first_arr, "index_json": index_json, "errorCode": 0,
                        "message": "ok"}, cls=DateEncoder))


# 获得报表中文字段
class ReportFields(APIView):
    authentication_classes = (JWTAuthentication,)

    def get(self, request, *args, **kwargs):
        data = {
            "type_name": {
                "label": "种类"
            },
            "product_name": {
                "label": "货品名称"
            },
            "plant_quantity": {
                "label": "厂内库存",
                "type": "DecimalField"
            },
            "port_quantity": {
                "label": "到港数量",
                "type": "DecimalField"
            },
            "not_arrival_port_quantity": {
                "label": "未到港数量",
                "type": "DecimalField"
            },
            "not_arrival_port_note": {
                "label": "未到岗备注"
            },
            "quantity": {
                "label": "合计数量",
                "type": "DecimalField"
            },
            "daily_consumption": {
                "label": "消耗计划/日",
                "type": "DecimalField"
            },
            "plant_quantity_available_day": {
                "label": "厂内库存可用天数",
                "type": "DecimalField"
            },
            "available_day": {
                "label": "总库存可用天数",
                "type": "DecimalField"
            },
            "safe_inventory": {
                "label": "安全库存按20天计",
                "type": "DecimalField"

            },
            "last_parchase_date": {
                "label": "最晚进料日期",
                "type": "DateField"
            },
            "purchase_quantity": {
                "label": "计划生产用量",
                "type": "DecimalField"
            },
            "actual_purchase_quantity": {
                "label": "计划采购量/月",
                "type": "DecimalField"
            }

        }
        return Response(data)


# 导出综合报表excel 改接口用于小程序 预览报表
from rest_framework.viewsets import ReadOnlyModelViewSet
from drf_renderer_xlsx.mixins import XLSXFileMixin
from drf_renderer_xlsx.renderers import XLSXRenderer


class UserDictExportViewset(XLSXFileMixin, ReadOnlyModelViewSet):
    queryset = PurchasePlan.objects.all()
    serializer_class = PurchasePlanSerializer
    authentication_classes = [JWTAuthentication, ]
    permission_classes = [BaseAuthPermission, ]
    renderer_classes = (XLSXRenderer,)
    filename = 'my_export.xlsx'
    column_header = {
        'titles': [
            "Column_1_name",
            "Column_2_name",
            "Column_3_name",
        ],
    }





# 导出综合报表excel 改接口用于小程序 预览报表
@api_view(['GET'])
@authentication_classes([JWTAuthentication])
def DownLoadComprehensiveReportView(request):
    """
        API文档下载
    :param request:
    :return:
    """
    if request.method == "GET":
        # import os
        # root = os.getcwd()  # 获得当前路径 /home/dir1
        # print
        # root
        # # 输出
        # # /home/dir1
        #
        # name = "file1"  # 定义文件名字
        # print(os.path.join(root, name))  # 合并路径名字和文件名字，并打印
        # # 输出
        # # /home/dir1/file1

        # 获取当前文件夹
        import os
        root = os.getcwd()  # 获取当前工作目录路径

        # 生成xlsx文件
        import pandas as pd

        data = getComprehensiveReportNoDict2()

        # 根据这个信息获得 excel的跨行逻辑
        data2 = getComprehensiveReport2()
        # ---------  处理 跨行逻辑
        arr = rowspanLogic2(data2)
        # 处理第一列的跨行逻辑
        first_arr = rowspanLogic(data2)

        data_df = pd.DataFrame(data)
        data_df.columns = ['id', '种类', '合计数量', '货品名称', '厂内库存', '未到港数量', '未到岗备注', '到港数量', '安全天数', '安全库存',
                           '总库存可用天数', '最晚进料日期', '计划采购量/月', '实际计划采购量', '分组id', '分组日消耗', '分组计划采购量/月', '分组合计']

        writer = pd.ExcelWriter(os.path.join(root, 'my.xlsx'))
        data_df.to_excel(writer, float_format='%.2f', index=False)
        writer.save()

        # 这里使用 openpyxl 合并单元格,添加单元格样式  pandas好像没有相关功能
        from openpyxl import load_workbook
        wb = load_workbook(filename=os.path.join(root, 'my.xlsx'))
        sheet1 = wb['Sheet1']

        # 计算安全天数
        row_index = 0
        for row in sheet1:
            # 跳过headers
            if row_index == 0:
                pass
            else:
                # 安全天数 = 库存总数 / 每日消耗 = quantity / daily_consumption
                # print(row[2])=quantity
                # print(row[15]=daily_consumption
                # print(row[10])=available_day
                if row[15].value is not None and Decimal(row[15].value) != 0:
                    row[10].value = Decimal(row[2].value) / Decimal(row[15].value)
                else:
                    row[10].value = None
            row_index += 1

        # 合并单元格
        for rowspan in first_arr:
            if rowspan['rowspan'] == 1:
                pass
            else:
                str_ = 'A' + str(rowspan['startIndex'] + 2) + ':' + 'A' + str(rowspan['endIndex'] + 1)
                sheet1.merge_cells(str_)
                str_ = 'B' + str(rowspan['startIndex'] + 2) + ':' + 'B' + str(rowspan['endIndex'] + 1)
                sheet1.merge_cells(str_)
        for rowspan_ in arr:
            if rowspan_['rowspan'] == 1:
                pass
            else:
                str_ = 'C' + str(rowspan_['startIndex'] + 2) + ':' + 'C' + str(rowspan_['endIndex'] + 1)
                sheet1.merge_cells(str_)
                str_ = 'I' + str(rowspan_['startIndex'] + 2) + ':' + 'I' + str(rowspan_['endIndex'] + 1)
                sheet1.merge_cells(str_)
                str_ = 'J' + str(rowspan_['startIndex'] + 2) + ':' + 'J' + str(rowspan_['endIndex'] + 1)
                sheet1.merge_cells(str_)
                str_ = 'K' + str(rowspan_['startIndex'] + 2) + ':' + 'K' + str(rowspan_['endIndex'] + 1)
                sheet1.merge_cells(str_)
                str_ = 'M' + str(rowspan_['startIndex'] + 2) + ':' + 'M' + str(rowspan_['endIndex'] + 1)
                sheet1.merge_cells(str_)
                str_ = 'O' + str(rowspan_['startIndex'] + 2) + ':' + 'O' + str(rowspan_['endIndex'] + 1)
                sheet1.merge_cells(str_)
                str_ = 'P' + str(rowspan_['startIndex'] + 2) + ':' + 'P' + str(rowspan_['endIndex'] + 1)
                sheet1.merge_cells(str_)
                str_ = 'Q' + str(rowspan_['startIndex'] + 2) + ':' + 'Q' + str(rowspan_['endIndex'] + 1)
                sheet1.merge_cells(str_)
                str_ = 'R' + str(rowspan_['startIndex'] + 2) + ':' + 'R' + str(rowspan_['endIndex'] + 1)
                sheet1.merge_cells(str_)

                # 增加背景色和边框
                from openpyxl.styles import PatternFill, Border, Side
                Color = ['FFFF00', '9c6500']  # 黄
                fille = PatternFill('solid', fgColor=Color[0])

                cell_border = Border(left=Side(style='thin'), right=Side(style='thin'),
                                     top=Side(style='thin'), bottom=Side(style='thin'))

                for i in range(3, 18 + 1):
                    for j in range(rowspan_['startIndex'] + 2, rowspan_['endIndex'] + 1 + 1):
                        sheet1.cell(row=j, column=i).fill = fille
                        sheet1.cell(row=j, column=i).border = cell_border

        # 自适应列宽
        wb = style_excel(wb, 'Sheet1')
        wb.save(filename=os.path.join(root, 'my.xlsx'))

        file = open(os.path.join(root, 'my.xlsx'), 'rb')
        response = HttpResponse(file)
        response['Content-Type'] = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
        response['Content-Disposition'] = 'attachment;filename="report.xlsx"'
        return response


# --------------------综合报表视图 相关结束


class ProductGroupView(BaseView):
    '''货品统计分组管理'''
    queryset = ProductGroup.objects.all().order_by('create_time')
    authentication_classes = (JWTAuthentication,)
    permission_classes = [BaseAuthPermission, ]
    throttle_classes = [VisitThrottle]
    serializer_class = ProductGroupSerializer
    filter_backends = (DjangoFilterBackend, SearchFilter, OrderingFilter,)
    search_fields = ('type_name',)
    ordering_fields = ('type_name', 'update_time', 'create_time',)
    filterset_fields = ['type_name']
    pagination_class = Pagination
